#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <pthread.h>
#define BACKLOG 5

class Param
{
public:
	Param(int sock, std::string ip, int port)
		: _sock(sock)
		, _ip(ip)
		, _port(port)
	{}
	~Param()
	{}
public:
	int _sock;
	std::string _ip;
	int _port;
};


class tcpserver
{
private:
    int _sockfd;
    int _port;

public:
    tcpserver(int port)
        : _sockfd(-1), _port(port)
    {}

    bool InitServer()
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            std::cerr << "socket fail!" << std::endl;
            return false;
        }
        std::cout << "socket success!" << std::endl;

        struct sockaddr_in local;
        memset(&local, '\0', sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;
        if (bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            std::cerr << "bind fail!" << std::endl;
            return false;
        }

        std::cout << "bind success!" << std::endl;

        if (listen(_sockfd, BACKLOG) < 0)
        {
            std::cerr << "listen fail!" << std::endl;
            return false;
        }

        std::cout << "listen success!" << std::endl;
        return true;
    }

public:
    void* HandlerRequest(void* arg)
	{
		pthread_detach(pthread_self()); //分离线程
		//int sock = *(int*)arg;
		Param* p = (Param*)arg;

		service(p->_sock, p->_ip, p->_port); //线程为客户端提供服务

		delete p; //释放参数占用的堆空间
		return nullptr;
	}

    void start()
    {
        for (;;)
        {
            struct sockaddr_in peer;
            memset(&peer, '\0', sizeof(peer));
            socklen_t len = sizeof(peer);
            // sock和listen套接字不一样.有区别.
            int sock = accept(_sockfd, (struct sockaddr *)&peer, &len);
            if (sock < 0)
            {
                std::cerr << "accept fail!" << std::endl;
                continue;
            }
            std::string client_ip = inet_ntoa(peer.sin_addr);
            int client_port = ntohs(peer.sin_port);
            std::cout << "get a new link-> " << sock << "[" << client_ip << "]" << client_port << std::endl;

            // // service(sock, client_ip, client_port);
            // //多进程版本;
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     //子进程;关闭监听套接字;
            //     close(_sockfd);
            //     //创建孙子进程;
            //     if(fork() > 0)
            //     {
            //         //退出爸爸进程;
            //         exit(0);
            //     }

            //     //孙子进程提供服务;
            //     service(sock, client_ip, client_port);
            //     exit(0);//孙子进程结束退出服务;
            // }
            // close(sock);//关闭为爸爸进程提供的服务套接字;
            // waitpid(id, nullptr, 0); //等待爸爸进程;

            // 多线程版本;

            Param* p = new Param(sock, client_ip, client_port);
			pthread_t tid;
			pthread_create(&tid, nullptr, HandlerRequest, p);
        }
    }

    void service(int sock, std::string client_ip, int client_port)
    {
        char buff[1024];
        while (true)
        {
            ssize_t size = read(sock, buff, sizeof(buff) - 1);
            if (size > 0)
            {
                buff[size] = '\0';
                std::cout << "get a new link-> " << sock << "[" << client_ip << "]" << client_port << buff << std::endl;
                write(sock, buff, size);
            }
            else if (size == 0)
            {
                std::cout << client_ip << " : " << client_port << " close" << std::endl;
                break;
            }
            else
            {
                std::cout << sock << "read fail!" << std::endl;
                break;
            }
        }
        close(sock);
        std::cout << client_ip << ":" << client_port << "service done!" << std::endl;
    }

    ~tcpserver()
    {
        if (_sockfd >= 0)
        {
            close(_sockfd);
        }
    }
};

void Usage(std::string s)
{
    std::cout << "Usage: " << s << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }

    int port = atoi(argv[1]);
    tcpserver *sur = new tcpserver(port);
    sur->InitServer();
    sur->start();
    return 0;
}